package com.df.hotfix.loader;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class HotFixLoader extends ClassLoader {

    String checkPath = "D:\\MyProject\\bakend\\java\\my_test\\hotfix\\src\\main\\java";
    JavaCompiler compiler = null;
    MyJavaFileManager myJavaFileManager;

    public HotFixLoader() {
        compiler = ToolProvider.getSystemJavaCompiler();
        // 自定义 JavaFileManager 方便自定义输入和输出
        myJavaFileManager = new MyJavaFileManager(compiler.getStandardFileManager(null, null, StandardCharsets.UTF_8));
    }

    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        if (name.startsWith("com.df.hotfix.scripts.impl")) {
            Class<?> aClass = this.findClass(name);
            if (aClass == null) {
                return this.getParent().loadClass(name);
            }
            return aClass;
        } else {
            return this.getParent().loadClass(name);
        }
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        String path = checkPath + File.separator + name.replace(".", "/") + ".java";
        JavaCompiler.CompilationTask task = null;
        try {
            task = compiler
                    .getTask(null, myJavaFileManager, null, null, null,
                            Arrays.asList(new InputFileJavaFileObject(new File(path), name)));
            // 同步调用
            task.call();
            OutputFileJavaFileObject outputFileJavaFileObject = myJavaFileManager.getByteArrayJavaFileObjects().stream().findAny().get();

            ByteArrayOutputStream o = (ByteArrayOutputStream) outputFileJavaFileObject.openOutputStream();
            // 获取字节码
            byte[] classByteArray = o.toByteArray();
            return defineClass(name, classByteArray, 0, classByteArray.length);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }
}
